import { getHash } from '@moretime/util/mock'

type EventItem = {
  /** 唯一标识 */
  uid: string;
  /** 触发事件名称 */
  key: string;
  /** 是否只触发一次 */
  isOnce?: boolean;
  /** 触发函数 */
  fn: Function;
}

/** 事件池 */
const pools: EventItem[] = []
/** 根据key获取事件集合 */
const getItemByKey    = (key: EventItem['key']) => pools.filter(k => k.key === key);
/** 根据uid获取事件集合下标 */
const getItemIdxByUid = (uid: EventItem['uid']) => pools?.findIndex(k => k.uid === uid);
/** 移除事件集合 */
const removeItem      = (uid: EventItem['uid']) => pools.splice(getItemIdxByUid(uid), 1);

/** useEvents
 * @description 事件管理器
 * @example
 * ```ts
 * const { emit, on, off, once } = useEvents();
 *
 * on('hello', (msg: string) => console.log(`hello, ${msg}`))
 * emit('hello', 'world') // hello, world
 * emit('hello', 'world') // hello, world
 * off('hello')
 * emit('hello', 'world') // nothing
 *
 * once('once', (msg: string) => console.log(`once, ${msg}`))
 * emit('once', 'world') // once, world
 * emit('once', 'world') // nothing
 * ```
 */
export default () => {
  return {
    /** 触发事件
     * @description 向事件管理器发送一个事件触发， 与useEvents.on成对使用
     * @param key 事件名称
     * @param args 事件参数
     */
    emit(key: EventItem['key'], ...args: any[]) {
      getItemByKey(key).forEach(item => {
        item.fn(...args);

        if (item.isOnce) removeItem(item.uid);
      })
    },
    /** 监听事件
     * @description 向事件管理器注册一个事件监听， 与useEvents.emit成对使用
     * @param key 事件名称
     * @param fn 事件回调
     */
    on(key: EventItem['key'], fn: Function) {
      pools.push({uid: getHash(`****-****-****-********-****`), key, fn})
    },
    /** 一次性事件监听
     * @description 向事件管理器注册一个一次性事件监听， 与useEvents.emit成对使用
     * @param key 事件名称
     * @param fn  事件回调
     */
    once(key: EventItem['key'], fn: Function) {
      pools.push({uid: '', key, fn, isOnce: true})
    },
    /** 移除事件监听
     * @param key 事件名称
     */
    off(key: EventItem['key']) {
      getItemByKey(key).forEach(k => removeItem(k.uid))
    },
  }
}